package com.uzai.console.aop;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.toolkit.IdWorker;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.uzai.common.utils.EsIndexName;
import com.uzai.console.annotation.SystemLogType;
import com.uzai.console.common.utils.DateUtil;
import com.uzai.console.common.utils.Tools;
import com.uzai.console.constant.CommonConstant;
import com.uzai.console.constant.ES.ElasticsearchUtil;
import com.uzai.console.entity.KefuUser;
import com.uzai.console.entity.Merchant;
import com.uzai.console.entity.es.EsUserOperationLog;
import com.uzai.console.enums.OperationTypeEnum;
import com.uzai.console.mapper.KefuUserMapper;
import com.uzai.console.mapper.MerchantMapper;
import com.uzai.console.vo.login.LoginVo;
import groovy.util.logging.Slf4j;
import io.swagger.annotations.ApiOperation;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author liuqi
 * @date 2021年12月10日 15:04
 */
@Component
@Aspect
@Slf4j
public class SysLogAspect {
    private Logger logger = LoggerFactory.getLogger(SysLogAspect.class);

    @Autowired
    public MerchantMapper merchantMapper;
    @Autowired
    public KefuUserMapper kefuUserMapper;
    @Autowired
    private ElasticsearchUtil elasticsearchUtil;

    //切点
    @Pointcut("@annotation(com.uzai.console.annotation.SystemLogType)")
    public void logPointcut(){}

    //后置通知
    @After("logPointcut()")
    public void afterLog(JoinPoint joinPoint) {
        //一般日志
        EsUserOperationLog esUserOerationLog = wrapSysLog(joinPoint);

        //插入到ES当中保存
        try{
            elasticsearchUtil.addData(esUserOerationLog, EsIndexName.UZAI_CONSOLE_USER_OPERATION_LOG, esUserOerationLog.getId());
        }catch (Exception e){
            logger.info("Es add error: index={},content={}",EsIndexName.UZAI_CONSOLE_USER_OPERATION_LOG, Tools.getStrEmpty(JSONObject.toJSONString(esUserOerationLog)));
        }

        //发送mq消息
        //stream.logOutput().send(MessageBuilder.withPayload(sysLog).build());
    }

    //异常通知
    @AfterThrowing(value = "logPointcut()", throwing = "e")
    public void throwingLog(JoinPoint joinPoint, Exception e) {
        //异常日志
        EsUserOperationLog esUserOerationLog = wrapSysLog(joinPoint);
        esUserOerationLog.setType(OperationTypeEnum.THROW.getKey());
        logger.info("Log值："+ Tools.getStrEmpty(JSONObject.toJSONString(esUserOerationLog)));
        //发送mq消息
        //stream.logOutput().send(MessageBuilder.withPayload(sysLog).build());
    }

    /**
     * 封装SysLog对象
     * @param joinPoint
     * @return
     */
    public EsUserOperationLog wrapSysLog(JoinPoint joinPoint){
        //获取请求响应对象
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        HttpServletRequest request = attributes.getRequest();
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        EsUserOperationLog esUserOerationLog = new EsUserOperationLog();

        //获取方法全路径
        //String methodName = signature.getDeclaringTypeName()+"."+signature.getName();
        //System.out.println(signature.getMethod());
        //System.out.println(signature.getParameterNames());

        //所有参数值
        Object[] args  = joinPoint.getArgs();
        try {
            esUserOerationLog.setPara(Tools.getStrEmpty(JSONObject.toJSONString(args)));
        }catch (Exception e){
            esUserOerationLog.setPara("");
        }

        //从header取出token
        LoginVo loginVo = (LoginVo)request.getAttribute(CommonConstant.LOGIN_MERCHANT_CONSOLE);

        //操作人信息
        esUserOerationLog.setId(String.valueOf(IdWorker.getId()));
        esUserOerationLog.setCreateTime(DateUtil.getNowTime());
        esUserOerationLog.setMerId(loginVo.getMerId());
        if (loginVo != null) {
            //是否通过默认账号登录
            if(Tools.getInteger(loginVo.getLoginByDefaultPassword()) == 1) { //是默认密码登录
                esUserOerationLog.setLoginType(1); //默认密码登录
            }else if(Tools.getInteger(loginVo.getLoginByDefaultPassword()) == 2){ //客服账号登录
                esUserOerationLog.setLoginType(2);
                esUserOerationLog.setManagerMobile(loginVo.getManagerMobile());
            }else{
                esUserOerationLog.setLoginType(0); //运营商常规登录
            }

            if(loginVo.getType()==1){ //子账号
                KefuUser kefuUser = kefuUserMapper.selectById(loginVo.getAccountId(), loginVo.getMerId());
                if(kefuUser != null){
                    esUserOerationLog.setAccount(kefuUser.getUser());
                }
            }else{
                Merchant merchant = merchantMapper.selectById(loginVo.getMerId());
                if(merchant != null){
                    esUserOerationLog.setAccount(merchant.getMobile());
                }
            }
        }

        //获取操作日记AOP注解
        SystemLogType systemLogType = signature.getMethod().getAnnotation(SystemLogType.class);
        if (systemLogType.type() != null){
            esUserOerationLog.setType(systemLogType.type().getKey());
            esUserOerationLog.setModel(systemLogType.model().getKey());
        }

        //获取controller注解参数值
        PostMapping postMapping = signature.getMethod().getAnnotation(PostMapping.class);
        if(postMapping != null){
            esUserOerationLog.setApi(Tools.getStrEmpty(JSONObject.toJSONString(postMapping.value())));
        }

        //操作内容
        String aspectOperatorLog = "";
        if(StringUtils.isNotBlank(esUserOerationLog.getPara())){
            JSONArray jsonArray = JSONObject.parseArray(esUserOerationLog.getPara());
            if(jsonArray != null && jsonArray.size() > 0){
                aspectOperatorLog = jsonArray.getJSONObject(0).getString("aspectOperatorLog");
            }
        }
        //如果操作内容为空，则将swagger的菜单名称作为操作内容
        if(StringUtils.isNotBlank(aspectOperatorLog)){
            esUserOerationLog.setContent(aspectOperatorLog);
        }else{
            //获取SWAGGER注解
            ApiOperation apiOperation = signature.getMethod().getAnnotation(ApiOperation.class);
            if(apiOperation != null){
                esUserOerationLog.setContent(Tools.getStrEmpty(JSONObject.toJSONString(apiOperation.value())));
            }
        }

        esUserOerationLog.setCreateTime(DateUtil.getNowTime());
        return esUserOerationLog;
    }
}
